package cn.sytton.taffe.web.flw.listener;

import cn.hutool.core.util.StrUtil;
import cn.sytton.taffe.framework.util.SpringContextUtil;
import cn.sytton.taffe.web.flw.entity.FormInstanceEntity;
import cn.sytton.taffe.web.flw.service.IFormInstanceService;
import lombok.extern.slf4j.Slf4j;
import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.ExecutionListener;
import org.camunda.bpm.engine.impl.bpmn.behavior.NoneEndEventActivityBehavior;
import org.camunda.bpm.engine.impl.bpmn.behavior.NoneStartEventActivityBehavior;
import org.camunda.bpm.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
import org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity;
import org.camunda.bpm.engine.impl.pvm.delegate.ActivityBehavior;

import javax.annotation.Resource;
import java.util.Objects;

import static cn.sytton.taffe.web.flw.help.constant.*;

/**
 * 流程监听服务
 *
 * @author skyrock
 */
@Slf4j
public class ProcessListener implements ExecutionListener {

    @Override
    public void notify(DelegateExecution delegateExecution) throws Exception {
        String event = delegateExecution.getEventName();
        ActivityBehavior ab = ((ExecutionEntity) delegateExecution).getActivity().getActivityBehavior();
        if (ab instanceof UserTaskActivityBehavior) {
            notifyBusiness(create(delegateExecution).setActivityType(ACTIVITY_TYPE.TASK));
        } else if (ab instanceof NoneStartEventActivityBehavior) {
            if (event.equals(FLOW_LISTENER_EVENT.END.toString())) {
                //流程启动时只记录end事件
                notifyBusiness(create(delegateExecution).setActivityType(ACTIVITY_TYPE.START));
            }
        } else if (ab instanceof NoneEndEventActivityBehavior) {
            if (event.equalsIgnoreCase(FLOW_LISTENER_EVENT.START.toString())) {
                //流程结束时只记录start事件
                notifyBusiness(create(delegateExecution).setActivityType(ACTIVITY_TYPE.END));
            }
        }
    }

    private ProcessListenerEntity create(DelegateExecution de) {
        return new ProcessListenerEntity()
                .setEvent(FLOW_LISTENER_EVENT.valueOf(de.getEventName().toUpperCase()))
                .setProcessKey(((ExecutionEntity) de).getProcessDefinition().getKey())
                .setProcessDefId(de.getProcessDefinitionId())
                .setProcessInstanceId(de.getProcessInstanceId())
                .setBusinessId(de.getBusinessKey())
                .setTaskId(de.getCurrentActivityId())
                .setTaskName(de.getCurrentActivityName())
                .setTenantId(de.getTenantId())
                .setVariables(de.getVariables())
                .setFormInstance(!Objects.isNull(de.getVariables())
                        ? de.getVariables().containsKey(FLOW_VARS_FORM_INSTANCE)
                            ? (FormInstanceEntity)de.getVariables().get(FLOW_VARS_FORM_INSTANCE)
                            : null
                        : null);
    }

    private void notifyBusiness(ProcessListenerEntity entity) {
        notifyFormInstance(entity);
        String beanId = StrUtil.lowerFirst(entity.getProcessKey()) + "FlowListener";
        if (SpringContextUtil.containsBean(beanId)) {
            try {
                IFlowListener impl = SpringContextUtil.getBean(beanId);
                impl.notify(entity);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
    }

    private void notifyFormInstance(ProcessListenerEntity entity) {
        IFormInstanceService service = SpringContextUtil.getBean("formInstanceService");
        service.flowListener(entity);
    }
}
